﻿using System;
using System.Collections;
using System.Diagnostics;

namespace TrueCode.Core.Diagnostics
{
	public static class DebugAssert
	{
		#region Null/IsNotNull
		public static bool IsNotNull( object argument )
		{
			return IsNotNull( argument, null );
		}

		public static bool IsNotNull( object argument, string message )
		{
#if DEBUG
			Debug.Assert( null != argument, message, new StackTrace().ToString() );
#endif
			return null != argument;
		}

		public static bool IsNotEmpty( string argument )
		{
			return IsNotEmpty( argument, null );
		}

		public static bool IsNotEmpty( string argument, string message )
		{
#if DEBUG
			Debug.Assert( ! string.IsNullOrEmpty( argument ), message, new StackTrace( ).ToString( ) );
#endif
			return !string.IsNullOrEmpty( argument );
		}

		public static bool IsNotEmpty(ICollection collection)
		{
			return IsNotEmpty(collection, null);
		}

		public static bool IsNotEmpty(ICollection collection, string message)
		{
#if DEBUG
			bool isNullOrEmpty = collection == null || collection.Count == 0;
			Debug.Assert( !isNullOrEmpty, message, new StackTrace().ToString() );
#endif
			return collection != null && collection.Count > 0;
		}

		public static bool IsNull( object argument )
		{
			return IsNull( argument, null, null );
		}

		public static bool IsNull( object argument, string message )
		{
			return IsNull( argument, message, null );
		}

		public static bool IsNull( object argument, string message, string detailMessage )
		{
#if DEBUG
			var call_stcak = new StackTrace( );
			var detail = string.Concat( detailMessage, call_stcak.ToString( ) );

			Debug.Assert( argument == null, message, detail );
#endif		
			return argument == null;
		}
		#endregion

		#region Bool
		public static bool IsTrue(bool expression)
		{
			return IsTrue(expression, null, null);
		}

		public static bool IsTrue(bool expression, string message)
		{
			return IsTrue(expression, message, null);
		}

		public static bool IsTrue(bool expression, string message, string detailMessage)
		{
#if DEBUG
			var call_stcak = new StackTrace();
			var detail = string.Concat(detailMessage, call_stcak.ToString());

			Debug.Assert(expression, message, detail);
#endif
// ReSharper disable ConditionIsAlwaysTrueOrFalse
			return expression;
// ReSharper restore ConditionIsAlwaysTrueOrFalse
		}

		public static bool IsFalse(bool expression)
		{
			return IsFalse(expression, null, null);
		}

		public static bool IsFalse(bool expression, string message)
		{
			return IsFalse(expression, message, null);
		}

		public static bool IsFalse(bool expression, string message, string detailMessage)
		{
#if DEBUG
			var call_stcak = new StackTrace();
			var detail = string.Concat(detailMessage, call_stcak.ToString());
			Debug.Assert(!expression, message, detail);
#endif
// ReSharper disable ConditionIsAlwaysTrueOrFalse
			return !expression;
// ReSharper restore ConditionIsAlwaysTrueOrFalse
		}
		#endregion

		public static bool AssertIsNot< T >(this T actual, T notExpected)
		{
			bool result = Equals(actual, notExpected);
#if DEBUG
			Debug.Assert(result);
#endif

// ReSharper disable ConditionIsAlwaysTrueOrFalse
			return result;
// ReSharper restore ConditionIsAlwaysTrueOrFalse
		}

		public static bool AssertIsTrue(this bool expression)
		{
			return IsTrue(expression);
		}

		public static bool AssertIsFalse(this bool expression)
		{
			return IsFalse(expression);
		}

		public static bool AssertIsNotNull< T >(this T argument) where T : class
		{
			return IsNotNull(argument);
		}

		public static bool AssertIsNotEmpty( this ICollection collection )
		{
			return IsNotEmpty( collection );
		}

		public static bool AssertIsGreaterThan<T>(this T value, T compareValue) where T : IComparable<T>
		{
			return IsTrue(value.CompareTo(compareValue) > 0);
		}

		public static bool AssertionFailed( this bool value )
		{
			return !value;
		}

		#region Not implemented
		public static void NotImplemented( )
		{
			NotImplemented( null );
		}

		public static void NotImplemented( string detailMessage )
		{
			var stackTrace = new StackTrace( );
			var detail = string.Concat( detailMessage, stackTrace.ToString( ) );

			Debug.Fail( "Method is not implemented", detail );
		}
		#endregion

		#region Exception
		public static void Exception( Exception exception )
		{
			Debug.Fail( exception.Message, exception.StackTrace );
		}
		#endregion

		public static void Fail( string message )
		{
			Debug.Fail( message );
		}
	}
}
